﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using AmiEmuLib.AmigaMachine.AmigaCPU;
using AmiEmuLib.AmigaMachine;
using System.Xml;
using System.Diagnostics;
using TomanuExtensions;

namespace AmiEmuLib.SaveState
{
    /// <summary>
    /// MC68020 state.
    /// </summary>
    public class CPU68020State : CPU680x0State
    {
        /// <summary>
        /// Prefetch.
        /// </summary>
        [DebuggerDisplay("{Hex.UIntToHex(IR)}")]
        public uint IR { get; private set; }

        /// <summary>
        /// Prefetch.
        /// </summary>
        [DebuggerDisplay("{Hex.UIntToHex(IRC)}")]
        public uint IRC { get; private set; }

        /// <summary>
        /// Master stack pointer.
        /// </summary>
        [DebuggerDisplay("{Hex.UIntToHex(MSP)}")]
        public uint MSP { get; private set; }

        /// <summary>
        /// Interrupt stack pointer.
        /// </summary>
        [DebuggerDisplay("{Hex.UIntToHex(ISP)}")]
        public uint ISP { get; private set; }

        /// <summary>
        /// User stack pointer.
        /// </summary>
        [DebuggerDisplay("{Hex.UIntToHex(USP)}")]
        public uint USP { get; private set; }

        /// <summary>
        /// Destination function code.
        /// </summary>
        public byte DFC { get; private set; }

        /// <summary>
        /// Source function code.
        /// </summary>
        public byte SFC { get; private set; }

        /// <summary>
        /// Vectors base address.
        /// </summary>
        [DebuggerDisplay("{Hex.UIntToHex(VBR)}")]
        public uint VBR { get; private set; }

        /// <summary>
        /// Cache control register.
        /// </summary>
        [DebuggerDisplay("{AmiEmuLib.AmigaMachine.AmigaCPU.CACRRegistry.Info()}")]
        public uint CACR { get; private set; }

        /// <summary>
        /// Cache address register.
        /// </summary>
        [DebuggerDisplay("{Hex.UIntToHex(CAAR)}")]
        public uint CAAR { get; private set; }

        /// <summary>
        /// Status register.
        /// </summary>
        [DebuggerDisplay("{AmiEmuLib.AmigaMachine.AmigaCPU.SR68020.Info(SR)}, {AmiEmuLib.AmigaMachine.AmigaCPU.CCRRegistry.Info(SR)}")]
        public ushort SR { get; private set; }

        /// <summary>
        /// Constructor.
        /// </summary>
        internal CPU68020State()
        {
        }

        /// <summary>
        /// Constructor.
        /// </summary>
        /// <param name="a_cpu"></param>
        /// <param name="a_prev"></param>
        internal CPU68020State(CPU68020 a_cpu, CPU68020State a_prev = null)
            : base(a_cpu, a_prev)
        {
            IR = a_cpu.IR;
            IRC = a_cpu.IRC;

            MSP = a_cpu.MSP;
            ISP = a_cpu.ISP;
            USP = a_cpu.USP;

            DFC = a_cpu.DFC;
            SFC = a_cpu.SFC;

            VBR = a_cpu.VBR;

            CACR = a_cpu.CACR;
            CAAR = a_cpu.CAAR;

            SR = a_cpu.SR;
        }

        /// <summary>
        /// Constructor.
        /// </summary>
        /// <param name="a_prev"></param>
        internal CPU68020State(CPU680x0State a_prev) 
            : base(a_prev)
        {
        }

        internal override void Restore(CPU680x0 a_cpu)
        {
            CPU68020 cpu = (CPU68020)a_cpu;

            cpu.IR = IR;
            cpu.IRC = IRC;

            cpu.MSP = MSP;
            cpu.ISP = ISP;
            cpu.USP = USP;

            cpu.DFC = DFC;
            cpu.SFC = SFC;

            cpu.VBR = VBR;

            cpu.CAAR = CAAR;
            cpu.CACR = CACR;

            cpu.SR = SR;

            base.Restore(a_cpu);
        }

        /// <summary>
        /// Restore state from another state.
        /// </summary>
        /// <param name="Prev"></param>
        protected override void Restore(CPU680x0State a_cpu)
        {
            base.Restore(a_cpu);

            CPU68020State cpu = (CPU68020State)a_cpu;

            IR = cpu.IR;
            IRC = cpu.IRC;

            MSP = cpu.MSP;
            ISP = cpu.ISP;
            USP = cpu.USP;

            DFC = cpu.DFC;
            SFC = cpu.SFC;

            VBR = cpu.VBR;

            CACR = cpu.CACR;
            CAAR = cpu.CAAR;

            SR = cpu.SR;
        }

        public override bool Equals(object a_obj)
        {
            if (a_obj == null)
                return false;
            CPU68020State cpu = a_obj as CPU68020State;
            if (cpu == null)
                return false;

            return base.Equals(a_obj) &&
                   (IR == cpu.IR) &&
                   (IRC == cpu.IRC) &&
                   (MSP == cpu.MSP) &&
                   (ISP == cpu.ISP) &&
                   (USP == cpu.USP) &&
                   (DFC == cpu.DFC) &&
                   (SFC == cpu.SFC) &&
                   (VBR == cpu.VBR) &&
                   (CACR == cpu.CACR) &&
                   (CAAR == cpu.CAAR) &&
                   (SR == cpu.SR);
        }

        public override int GetHashCode()
        {
            return base.GetHashCode() ^ 
                   IR.GetHashCode() ^
                   IRC.GetHashCode() ^
                   MSP.GetHashCode() ^
                   ISP.GetHashCode() ^
                   USP.GetHashCode() ^
                   DFC.GetHashCode() ^
                   SFC.GetHashCode() ^
                   VBR.GetHashCode() ^
                   CACR.GetHashCode() ^
                   CAAR.GetHashCode() ^
                   SR.GetHashCode();
        }

        internal override void ReadXml(XmlReader a_reader)
        {
            if (a_reader.IsEmptyElement)
            {
                a_reader.ReadStartElement(GetType().Name);
                return;
            }

            a_reader.ReadStartElement(GetType().Name);

            base.ReadXml(a_reader);

            if (a_reader.IsStartElement("IR"))
                IR = a_reader.ReadElementContentAsHexUInt("IR");
            if (a_reader.IsStartElement("IRC"))
                IRC = a_reader.ReadElementContentAsHexUInt("IRC");

            if (a_reader.IsStartElement("MSP"))
                MSP = a_reader.ReadElementContentAsHexUInt("MSP");
            if (a_reader.IsStartElement("ISP"))
                ISP = a_reader.ReadElementContentAsHexUInt("ISP");
            if (a_reader.IsStartElement("USP"))
                USP = a_reader.ReadElementContentAsHexUInt("USP");

            if (a_reader.IsStartElement("DFC"))
                DFC = a_reader.ReadElementContentAsHexByte("DFC");
            if (a_reader.IsStartElement("SFC"))
                SFC = a_reader.ReadElementContentAsHexByte("SFC");

            if (a_reader.IsStartElement("VBR"))
                VBR = a_reader.ReadElementContentAsHexUInt("VBR");

            if (a_reader.IsStartElement("CACR"))
                CACR = a_reader.ReadElementContentAsHexUInt("CACR");
            if (a_reader.IsStartElement("CAAR"))
                CAAR = a_reader.ReadElementContentAsHexUInt("CAAR");

            if (a_reader.IsStartElement("SR"))
                SR = a_reader.ReadElementContentAsHexUShort("SR");

            a_reader.ReadEndElement();
        }

        internal override void WriteXml(XmlWriter a_writer)
        {
            base.WriteXml(a_writer);

            CPU68020State prev = (CPU68020State)Prev;

            if (((prev != null) && (prev.IR != IR)) || (prev == null))
                a_writer.WriteHexElement("IR", IR);
            if (((prev != null) && (prev.IRC != IRC)) || (prev == null))
                a_writer.WriteHexElement("IRC", IRC);

            if (((prev != null) && (prev.MSP != MSP)) || (prev == null))
                a_writer.WriteHexElement("MSP", MSP);
            if (((prev != null) && (prev.ISP != ISP)) || (prev == null))
                a_writer.WriteHexElement("ISP", ISP);
            if (((prev != null) && (prev.USP != USP)) || (prev == null))
                a_writer.WriteHexElement("USP", USP);

            if (((prev != null) && (prev.DFC != DFC)) || (prev == null))
                a_writer.WriteHexElement("DFC", DFC);
            if (((prev != null) && (prev.SFC != SFC)) || (prev == null))
                a_writer.WriteHexElement("SFC", SFC);

            if (((prev != null) && (prev.VBR != VBR)) || (prev == null))
                a_writer.WriteHexElement("VBR", VBR);

            if (((prev != null) && (prev.CACR != CACR)) || (prev == null))
                a_writer.WriteHexElement("CACR", CACR);
            if (((prev != null) && (prev.CAAR != CAAR)) || (prev == null))
                a_writer.WriteHexElement("CAAR", CAAR);

            if (((prev != null) && (prev.SR != SR)) || (prev == null))
                a_writer.WriteHexElement("SR", SR);
        }
    }
}
